package com.eastedu.report.principal.util;

import com.eastedu.common.enums.SubjectType;
import com.eastedu.report.principal.model.PeriodAndSubjectReportData;
import org.apache.commons.lang3.StringUtils;

import java.text.MessageFormat;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 校长月报报告描述工具
 *
 * @author superman
 */
public interface ReportDescriptionUtil {

    /**
     * 基于学届和学科的数据描述，需要统计最大值和最小值，例如：xxx最多/最少，为x个，xxx最高/最低为xx%，xxx未使用过等
     * <p>
     * 注意：
     * * 该函数目前只在‘同步教学’、‘同步教研’数据描述中使用，如果后续有其他相似数据图表需要使用该函数，请自行测试
     * * 如果需要修改该函数，请通知其他使用该函数的同事
     *
     * @param <T>       the type parameter
     * @param usages    the usages
     * @param predicate the predicate
     * @param function  the function
     * @return the function
     */
    static <T extends PeriodAndSubjectReportData> BiFunction<Map<String, String>, Function<Number, String>, String> minAndMaxDescription(List<T> usages,
                                                                                                                                         Predicate<T> predicate,
                                                                                                                                         Function<T, Number> function) {
        return (description, formatter) -> {
            // * 分组，并过滤掉0或者null以及学届为空的数据
            Map<Number, List<T>> groupData = usages.stream()
                    .filter(data -> StringUtils.isNotBlank(data.getSchoolPeriod()))
                    .filter(predicate)
                    .collect(Collectors.groupingBy(function));

            // 获取为0的数据（排除null、非0以及学届为空的数据）
            Map<Number, List<T>> zeroGroupData = usages.stream()
                    .filter(data -> StringUtils.isNotBlank(data.getSchoolPeriod()))
                    .filter(teacherFollowedTeachingReportData -> Objects.nonNull(function.apply(teacherFollowedTeachingReportData)))
                    .filter(teacherFollowedTeachingReportData -> !predicate.test(teacherFollowedTeachingReportData))
                    .collect(Collectors.groupingBy(function));

            Set<Number> groupKeys = groupData.keySet();
            Optional<Number> maxOptional = groupKeys.stream().max(Comparator.comparing(Number::doubleValue));
            Optional<Number> minOptional = groupKeys.stream().min(Comparator.comparing(Number::doubleValue));
            // * 计算最大值（因为已经过滤了0或者null的数据，所以计算出来的最大值和最小值可能不存在），如果不存在则直接输出“各学届各学科教师均未直播参与同步备课”
            return maxOptional.map(max -> {
                List<T> maxLiveRateData = groupData.get(max);
                String value = MessageFormat.format(description.get("max"),
                                                    maxLiveRateData.stream()
                                                            .sorted(Comparator.comparing(T::getSchoolPeriod).thenComparing(data -> SubjectType.getByCode(data.getSubjectCode()).ordinal()))
                                                            .map(data -> data.getSchoolPeriod() + SubjectType.getByCode(data.getSubjectCode()).getName())
                                                            .collect(Collectors.joining("、")),
                                                    formatter.apply(max));

                // 因为已经过滤了为0的数据，如果代码走到了这里，那么为0的肯定是存在的，所以直接取出为0的数据
                Set<Number> keys = zeroGroupData.keySet();
                value += keys.stream()
                        .filter(key -> key.intValue() == 0)
                        .map(zeroGroupData::get)
                        .filter(Objects::nonNull)
                        .findFirst()
                        .map(minLiveRateData -> MessageFormat.format(description.get("zero"),
                                                                     minLiveRateData.stream()
                                                                             .sorted(Comparator.comparing(T::getSchoolPeriod).thenComparing(data -> SubjectType.getByCode(data.getSubjectCode()).ordinal()))
                                                                             .map(data -> data.getSchoolPeriod() + SubjectType.getByCode(data.getSubjectCode()).getName())
                                                                             .collect(Collectors.joining("、"))))
                        .orElseGet(() -> {
                            // * 计算最小值（因为已经过滤了0或者null的数据，所以计算出来的最大值和最小值可能不存在），如果不存在则查询为0的数据，并输出 “xx（学届）xx（学科名称）的学科教师暂未xxx。”
                            return minOptional.map(min -> {
                                if (max.equals(min)) {
                                    return "";
                                }
                                List<T> minLiveRateData = groupData.get(min);
                                return MessageFormat.format(description.get("min"),
                                                            minLiveRateData.stream()
                                                                    .sorted(Comparator.comparing(T::getSchoolPeriod).thenComparing(data -> SubjectType.getByCode(data.getSubjectCode()).ordinal()))
                                                                    .map(data -> data.getSchoolPeriod() + SubjectType.getByCode(data.getSubjectCode()).getName())
                                                                    .collect(Collectors.joining("、")),
                                                            formatter.apply(min));
                            }).orElse("");
                        });
                return value;
            }).orElseGet(() -> description.get("never")) + "。";
        };
    }
}
